const HashTable = require('../hashTable/hashTable');

module.exports = class TrieNode {
  constructor(character, isCompleteWord = false) {
    // 每一个节点对应的字符
    this.character = character;
    // 该节点是否已经组成完整的单词
    this.isCompleteWord = isCompleteWord;
    // 子节点
    this.children = new HashTable();
  }
  getChild(character) {
    // 获取对应的子节点，实际上是先将字符转换为hash，找到对应的bucket，再根据对应的node找到链表里面的节点
    return this.children.get(character);
  }
  addChild(character, isCompleteWord = false) {
    // 如果对应的子节点不在哈希表里面了，先创建一个节点，把放入到哈希表里面
    if (!this.hasChild(character)) {
      this.children.set(character, new TrieNode(character, isCompleteWord));
    }
    const childNode = this.children.get(character);

    childNode.isCompleteWord = childNode.isCompleteWord || isCompleteWord;
    return childNode;
  }
  removeChild(character) {
    const childNode = this.getChild(character);
    // 删除子节点满足以下几个条件
    /**
     * 1、对应子节点存在
     * 2、该节点不是末尾节点
     * 3、该节点还有子节点
     */
    // 例如：find和findBy两个word，现在要删除d，如果只有find这个word是可以删除的，但是如果
    // 存在findBy，那么Trie('d').isCompleteWord  = true，并且 Trie('d')的children还有
    // Trie('B')和Trie('y')
    if (
      childNode
      && !childNode.isCompleteWord
      && !childNode.hasChildren()
    ) {
      this.children.delete(character);
    }

    return this;
  }
  hasChild(character) {
    // 查找当前节点是否有对应的子节点，就是去哈希表里面查询是否有对应的hash，并返回
    return this.children.has(character);
  }
  hasChildren() {
    // 查找当前节点是否有子节点，跟hashChild不同，不会去查询对应的hash，而是直接查看keys里面是否有key，也不返回对应的子节点
    return this.children.getKeys().length !== 0;
  }
  suggestChildren() {
    // 返回所有的单词的字符串
    // 例如：word => ['w', 'o', 'r', 'd']
    return [...this.children.getKeys()];
  }
  toString() {
    // 返回当前节点对应的字符串
    // word => 如果是TrieNode('w').toString() => w*:word
    // word => 如果是TrieNode('o').toString() => o:ord
    let childrenAsString = this.suggestChildren().toString();
    childrenAsString = childrenAsString ? `:${childrenAsString}` : '';
    const isCompleteString = this.isCompleteWord ? '*' : '';

    return `${this.character}${isCompleteString}${childrenAsString}`;
  }
}